#include <stdio.h>        // 标准输入输出头文件
#include <stdlib.h>       // 标准库头文件
#include <string.h>       // 字符串操作头文件
#include <time.h>         // 时间相关函数头文件
#include <unistd.h>       // UNIX 标准函数定义
#include <signal.h>       // 信号处理头文件
#include <sqlite3.h>      // SQLite3 库头文件
#include <errno.h>        // 错误号定义，用于 errno
#include <getopt.h>       // 命令行选项解析头文件

#include "read_temperature.h" // 包含读取温度的头文件
#include "database.h"         // 包含数据库操作的头文件
#include "connection.h"       // 包含连接操作的头文件
#include "get_device_id.h"       // 包含获取id的头文件

#define MAX_BUFFER 512        // 定义最大缓冲区大小
#define BUFFER_SIZE 1024      // 定义缓冲区大小

// 信号处理函数，忽略 SIGPIPE 信号
void handle_sigpipe(int sig)
{
    printf("收到 SIGPIPE 信号，可能连接已断开。\n"); // 打印提示信息
}


int main(int argc, char *argv[])
{
    char  data[MAX_BUFFER];                  // 用于存储设备数据的缓冲区
    char  *server_ip = NULL;                 // 服务器 IP 地址
    int   server_port = -1;                   // 服务器端口号
    int   interval_seconds = -1;              // 采样间隔时间
    char  device_id[20];                           //设备id
    // 命令行参数解析
    int opt;
    while ((opt = getopt(argc, argv, "i:p:s:")) != -1) 
    {
        switch (opt) 
        {
            case 'i':
                server_ip = optarg; // 获取服务器 IP 地址
                break;
            case 'p':
                server_port = atoi(optarg); // 获取服务器端口号
                break;
            case 's':
                interval_seconds = atoi(optarg); // 获取采样间隔时间
                break;
            default:
                fprintf(stderr, "用法: %s -i <服务器IP> -p <服务器端口> -s <采样间隔>\n", argv[0]); // 打印用法提示
                exit(EXIT_FAILURE);
        }
    }

    // 检查必需的参数是否提供
    if (server_ip == NULL || server_port == -1 || interval_seconds == -1) 
    {
        fprintf(stderr, "错误: 必须提供服务器IP、服务器端口和采样间隔。\n"); // 打印错误信息
        fprintf(stderr, "用法: %s -i <服务器IP> -p <服务器端口> -s <采样间隔>\n", argv[0]); // 打印用法提示
        exit(EXIT_FAILURE);
    }
    
    memset(device_id,0,sizeof(device_id));
    if(!get_device_id(device_id,sizeof(device_id)))
    {
        printf("获取设备id失败\n");
        return -1;
    }


    // 打印配置信息
    printf("服务器地址: %s\n", server_ip);
    printf("端口号: %d\n", server_port);
    printf("采样间隔（秒）: %d\n", interval_seconds);
    printf("设备id: %s\n", device_id);

    sqlite3 *db;  // SQLite 数据库指针
    int rc;       // 返回码

    // 服务器连接标志位和套接字描述符
    int server_connected = 0;  // 服务器连接状态标志，0 表示未连接，1 表示已连接
    int sock = -1;             // 套接字描述符

    // 捕获并忽略 SIGPIPE 信号，防止向已关闭的套接字写入时程序崩溃
    signal(SIGPIPE, SIG_IGN);

    // 打开 SQLite 数据库
    rc = sqlite3_open("temperature_data.db", &db);
    if (rc != SQLITE_OK)
    {
        fprintf(stderr, "无法打开 SQLite 数据库: %s\n", sqlite3_errmsg(db)); // 打印错误信息
        return -1;
    }

    // 检查并创建表
    create_table_if_not_exists(db);
    printf("SQLite 表已准备就绪。\n");

    // 尝试连接服务器
    sock = connect_to_server(server_ip, server_port);

    // 检查连接状态
    if (sock >= 0)
    {
        if (check_connection(sock))//调用连接函数，如果成功，则进入
        {
            server_connected = 1;  // 设置服务器连接标志位为 1
            printf("成功连接到服务器。\n");
        }
        else
        {
            server_connected = 0;
            printf("无法验证服务器连接状态，进入离线模式。\n");
            close(sock);
            sock = -1;
        }
    }
    else
    {
        server_connected = 0;
        printf("无法连接到服务器，进入离线模式。\n");
    }

    // 设置初始的上次记录时间为当前时间
    time_t last_recorded_time = time(NULL);

    // 主循环
    while (1)
    {
        // 获取当前时间
        time_t current_time = time(NULL);

        // 在主循环中处理数据发送逻辑
        if (!server_connected)//如果服务器断开，则尝试重连
        {
            sock = connect_to_server(server_ip, server_port);
            if (sock >= 0 && check_connection(sock))
            {
                server_connected = 1;
                printf("重新连接并验证服务器连接状态成功。\n");
            }
            else
            {
                server_connected = 0;
                printf("仍然无法连接到服务器。\n");
                if (sock >= 0)
                {
                    close(sock); // 关闭套接字
                    sock = -1;
                }
            }
        }
        else//服务器连接，判断连接是否依然有效果，针对异常断开的情况
        {
            if (!check_connection(sock))
            {
                server_connected = 0;
                close(sock); // 关闭套接字
                sock = -1;
            }
            else
            {
                printf("无需重新连接。\n");
            }
        }
        //如果服务器连接有效，并且sqlite数据中有数据，则发送一次数据
        if (server_connected && has_cached_data(db))
        {
            send_cached_data(db, sock);
        }

        // 在主循环中处理数据发送逻辑
        //采集时间到了，进入下面if
        if (difftime(current_time, last_recorded_time) >= interval_seconds)//到达采集时间
        {
            printf("\n在%s采集数据\n", ctime(&current_time));//打印采集的当前时间
            memset(data, 0, sizeof(data)); // 清空数据缓冲区
            float temp = read_temperature(); // 读取温度

            if (temp != -1)
            {
                char time_str[MAX_BUFFER];
                strftime(time_str, MAX_BUFFER, "%Y-%m-%d %H:%M:%S", localtime(&current_time)); // 格式化时间
                
                sprintf(data, "站点 ID: %s \n温度: %.2f°C\n时间: %s\n",device_id, temp, time_str); // 生成数据字符串

                printf("采集到的数据：\n%s\n", data); // 打印采集到的数据
                if (server_connected)
                {
                    if (send_data(sock, data) == -1)
                    {
                        server_connected = 0;
                        close(sock);
                        sock = -1;
                        printf("发送数据失败，进入离线模式。\n");
                        store_in_sqlite(db, data);
                        printf("数据已缓存到本地。\n");
                    }
                    else
                    {
                        printf("数据已发送到服务器。\n");
                    }
                }
                else
                {
                    store_in_sqlite(db, data);
                    printf("数据已缓存到本地。\n");
                }
            }
            else
            {
                printf("读取温度数据失败。\n");
            }

            last_recorded_time = current_time; // 更新上次记录时间
        }

        // 休眠一段时间，防止忙等待
        sleep(1);
    }

    // 关闭 SQLite 数据库（实际上不会到达这里）
    sqlite3_close(db);
    return 0;
}

